{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 误差函数（损失函数）\n",
    "\n",
    "前面我们的预测函数为：y = w * x + b\n",
    "\n",
    "计算误差的方式为：y_predict - y\n",
    "\n",
    "这样计算出来的误差可能是正数，也可能是负数。\n",
    "\n",
    "比如，x[1]对应样本的误差为2， x[2]对应样本的误差为-2， 那么x[1]和x[2]的误差和为0，导致误差被抵消了。\n",
    "\n",
    "一般我们会通过取误差的平方来解决这个问题，也叫做平方误差，计算方式为：(y_predict - y)^2，好处是：\n",
    "1. 误差平方之后，都为正数，从而避免误差被抵消\n",
    "2. 平方会放大误差，使得模型对误差更敏感\n",
    "3. 平方误差是一个平滑函数，便于求导"
   ],
   "id": "f98c75ba8cc11455"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ],
   "id": "e723b2e212ed15af"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.randint(100) for i in x])\n",
    "print(x[:5])\n",
    "print(y[:5])"
   ],
   "id": "27af8fe0f1918734"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "预测函数为：\n",
    "$$ y_{\\text{predict}} = w \\cdot x + b $$\n",
    "\n",
    "误差函数为：\n",
    "$$ \\text{loss} = (y_{\\text{predict}} - y)^2 $$\n",
    "\n",
    "带入y_predict，得到最终的误差函数为：\n",
    "$$ \\text{loss} = (w \\cdot x + b - y)^2 $$\n",
    "\n",
    "$x$, $y$ 是样本，是已知的，$w$, $b$是未知的，不同的$x$, $y$对应的误差不同\n",
    "\n",
    "所以，误差函数就是一个$w$和$w$为自变量，$loss$为因变量的二元二次函数"
   ],
   "id": "38234e86d7faa452"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "二元二次函数可能忘记了，我们先忽略b，这样误差函数为：\n",
    "$$ \\text{loss} = (w \\cdot x - y)^2 $$\n",
    "\n",
    "就变成了一个一元二次函数。\n",
    "\n"
   ],
   "id": "330dbd1c18856715"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "# 随机生成一些w的数据\n",
    "w = np.random.randint(-100, 100, 200)\n",
    "w.sort()\n",
    "print(w[:5])"
   ],
   "id": "4fcd913123b004cd"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "然后带入到误差函数中",
   "id": "e52568e45a5e0e96"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "loss = (w * x[1] - y[1]) ** 2\n",
    "print(loss[:5])"
   ],
   "id": "bfbec1bd964134ac"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "plt.plot(w, loss)\n",
    "plt.show()"
   ],
   "id": "996af75e17d7f551"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "所以误差函数：$$ \\text{loss} = (y_{\\text{predict}} - y)^2 $$\n",
    "就是是一条抛物线，纵坐标就是loss，因此纵坐标的最低点，就是误差最小的点。\n",
    "\n",
    "当然，预测函数y_predict如果不是线性函数，那么对应的误差函数可能就不是一条抛物线，而可能是一条复杂的曲线，但对于模型训练而言，训练的目的都是找到loss最小的点对应的w的值。"
   ],
   "id": "dfc330a616e6f32e"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "那么，如何找到最低点呢？这就需要梯度下降了。",
   "id": "f1f57e77b9dcd461"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 梯度下降\n",
    "\n",
    "什么是梯度？\n",
    "梯度，就是误差函数关于自变量w的导数。\n",
    "\n",
    "预测函数为：\n",
    "$y_{\\text{predict}} = w \\cdot x$\n",
    "\n",
    "误差函数为：\n",
    "$loss  = (y_{\\text{predict}} - y)^2 = (w \\cdot x - y)^2 $\n",
    "\n",
    "\n",
    "注意：$w$才是自变量，$x$和$y$这里要看做常量，比如某一个样本$x[i]$,$y[i]$ :\n",
    "\n",
    "$loss = (w \\cdot x[i] - y[i])^2$\n",
    "\n",
    "展开后为：\n",
    "\n",
    "$loss = x[i]^2 \\cdot w^2 - 2 \\cdot w \\cdot x[i] \\cdot y[i] + y[i]^2$\n",
    "\n",
    "那么，误差函数关于$w$的导数为：\n",
    "$dloss = x[i]^2 \\cdot 2 \\cdot w - 2 \\cdot x[i] \\cdot y[i] = 2 \\cdot x[i]^2 \\cdot w - 2 \\cdot x[i] \\cdot y[i]$\n",
    "\n",
    "这样，dloss就是在x[i]、x[i]这个样本上，误差函数对w的导数，w取不同的值，dloss的值就会不同。\n",
    "\n",
    "dloss如果等于0，那么w取这个值，误差就是最小的。"
   ],
   "id": "df92caf15e66b25c"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "画出w[10]位置的切线",
   "id": "58b8671462da03a3"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "# 模拟出有序的w\n",
    "w = np.random.randint(-100, 100, 200)\n",
    "w.sort()\n",
    "loss = (w * x[1] - y[1]) ** 2\n",
    "\n",
    "# 计算 w[10] 处的导数值\n",
    "pos = 10\n",
    "dloss = 2 * w[pos] * x[1] ** 2 - 2 * x[1] * y[1]\n",
    "\n",
    "# 在 w[10] 附近构造切线\n",
    "tangent_line_length = 10\n",
    "tangent_line = dloss * (w[pos - tangent_line_length:pos + tangent_line_length] - w[pos]) + loss[pos]\n",
    "\n",
    "# 画出原曲线和切线\n",
    "plt.plot(w, loss)\n",
    "plt.plot(w[pos - tangent_line_length:pos + tangent_line_length], tangent_line, 'r--')\n",
    "plt.scatter(w[pos], loss[pos], color='green', zorder=5)\n",
    "\n",
    "plt.xlabel(\"w\")\n",
    "plt.ylabel(\"Loss\")\n",
    "plt.show()\n",
    "\n",
    "# 导数小于0，左高右低\n",
    "print(dloss)"
   ],
   "id": "77a9aaaf7c77069c"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "画出w[110]位置的切线",
   "id": "aa50fd4fbc452d59"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "# 模拟出有序的w\n",
    "w = np.random.randint(-100, 100, 200)\n",
    "w.sort()\n",
    "loss = (w * x[1] - y[1]) ** 2\n",
    "\n",
    "# 计算 w[110] 处的导数值\n",
    "pos = 110\n",
    "dloss = 2 * w[pos] * x[1] ** 2 - 2 * x[1] * y[1]\n",
    "\n",
    "# 在 w[10] 附近构造切线\n",
    "tangent_line_length = 10\n",
    "tangent_line = dloss * (w[pos - tangent_line_length:pos + tangent_line_length] - w[pos]) + loss[pos]\n",
    "\n",
    "# 画出原曲线和切线\n",
    "plt.plot(w, loss)\n",
    "plt.plot(w[pos - tangent_line_length:pos + tangent_line_length], tangent_line, 'r--')\n",
    "plt.scatter(w[pos], loss[pos], color='green', zorder=5)\n",
    "\n",
    "plt.xlabel(\"w\")\n",
    "plt.ylabel(\"Loss\")\n",
    "plt.show()\n",
    "\n",
    "# 导数大于0，左低右高\n",
    "print(dloss)"
   ],
   "id": "8d8c49e6e2da9d25"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "所以，我们可以根据dloss的值来判断w的修改方向。\n",
    "\n",
    "dloss小于0，那就增加w\n",
    "dloss大于0，那就减少w\n",
    "\n",
    "这个过程就是梯度下降。\n",
    "\n",
    "因此，我们可以修改之前的模型训练代码，采用梯度下降的方式来进行训练。"
   ],
   "id": "90eb7f8e532ea942"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.rand() * 100 for i in x])\n",
    "\n",
    "print(x[:5])\n",
    "print(y[:5])\n",
    "\n",
    "x = x / 100\n",
    "y = y / 100\n",
    "\n",
    "epoch = 1\n",
    "w = 0.1\n",
    "\n",
    "\n",
    "for _ in range(epoch):\n",
    "    for i in range(len(x)):\n",
    "        dloss = 2 * w * x[i] ** 2 - 2 * x[i] * y[i]\n",
    "        w = w - dloss  # 斜率大，调整幅度就大\n",
    "\n",
    "y_predict = w * x\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, y_predict, color='r')\n",
    "plt.show()"
   ],
   "id": "17e077d363bdba36"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "上面的dloss值，就是梯度，所以叫做梯度下降。\n",
    "\n",
    "有了梯度下降，对于复杂的误差曲线，也能通过梯度下降的方式找到最低点。\n",
    "\n",
    "我们只需要基于预测函数，得到对应的误差函数，然后基于误差函数对w求导，就可以得到梯度，从而可以根据梯度调整w的值。"
   ],
   "id": "656cf1e2ac095676"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 导数、斜率、梯度\n",
    "### 导数\n",
    "导数的定义：对单变量函数 $ y = f(x) $，导数是函数在某个点的瞬时变化率：\n",
    "$$f'(x) = \\lim_{{\\Delta x \\to 0}} \\frac{f(x + \\Delta x) - f(x)}{\\Delta x}$$\n",
    "导数的几何意义：曲线在该点切线的斜率\n",
    "\n",
    "### 梯度\n",
    "梯度的定义：对多变量函数 $ f(x_1, x_2, \\dots, x_n) $（如 $ z = f(x, y) $），梯度是一个向量，是所有自变量方向上的偏导数构成的向量\n",
    "$$\n",
    "\\nabla f = \\left( \\frac{\\partial f}{\\partial x_1},  \\frac{\\partial f}{\\partial x_2},  \\dots,  \\frac{\\partial f}{\\partial x_n} \\right)\n",
    "$$\n",
    "函数 $ f(x, y) = x^2 + y^2 $ 的梯度是：\n",
    "  $$\n",
    "  \\nabla f = (2x, 2y)\n",
    "  $$"
   ],
   "id": "37856064b42272c0"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 常见函数的导数公式\n",
    "常数函数：$f(x) = c$的导数是0\n",
    "\n",
    "幂函数：$f(x) = x^n$的导数是$nx^{n-1}$\n",
    "\n",
    "指数函数：$f(x) = e^x$的导数是：$e^x$\n",
    "\n",
    "sin函数：$f(x) = sin(x)$的导数是：$cos(x)$\n",
    "\n",
    "cos函数：$f(x) = cos(x)$的导数是：$-sin(x)$\n",
    "\n",
    "sigmoid函数：$\\sigma(x) = \\frac{1}{1 + e^{-x}}$的导数是：$\\sigma(x) \\cdot (1 - \\sigma(x))$"
   ],
   "id": "ae8ad6f4ab2fa609"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 链式法则\n",
    "\n",
    "若 `y = f(g(x))`\n",
    "\n",
    "令 `u = g(x)`\n",
    "\n",
    "则 `y = f(u)`\n",
    "\n",
    "`dy/dx = (dy/du) * (du/dx)`\n",
    "\n",
    "\n",
    "例子:\n",
    "`f(x) = sin(x^2)`\n",
    "\n",
    "令`u = x^2`,\n",
    "\n",
    "则 `f = sin(u)`\n",
    "\n",
    "`df/dx = cos(u) * (du/dx) = cos(x^2) * 2x`\n"
   ],
   "id": "d5834d898d5b381f"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## SGD随机梯度下降\n",
    "SGD，是Stochastic Gradient Descent的缩写，即随机梯度下降，在每次迭代中，每次随机一个样本来更新w。"
   ],
   "id": "9c450d372bb7d14e"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.rand() * 100 for i in x])\n",
    "\n",
    "print(x[:5])\n",
    "print(y[:5])\n",
    "\n",
    "x = x / 100\n",
    "y = y / 100\n",
    "\n",
    "epoch = 200\n",
    "w = 0.1\n",
    "\n",
    "for _ in range(epoch):\n",
    "    # 随机选取一个样本（SGD 的核心）\n",
    "    i = np.random.randint(0, len(x))\n",
    "\n",
    "    dloss = 2 * w * x[i] ** 2 - 2 * x[i] * y[i]\n",
    "    w = w - dloss\n",
    "\n",
    "y_predict = w * x\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, y_predict, color='r')\n",
    "plt.show()"
   ],
   "id": "dc091c31303c813b"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 均方误差\n",
    "每次迭代，随机获取一部分样本来更新权重。\n",
    "\n",
    "对于一个批量而言，它的误差函数可以做如下推导。\n",
    "\n",
    "x[1]和y[1]这个样本的误差\n",
    "$loss1 = x[1]^2 \\cdot w^2 - 2 \\cdot w \\cdot x[1] \\cdot y[1] + y[1]^2$\n",
    "\n",
    "x[2]和y[2]这个样本的误差\n",
    "$loss2 = x[2]^2 \\cdot w^2 - 2 \\cdot w \\cdot x[2] \\cdot y[2] + y[2]^2$\n",
    "\n",
    "x[n]和y[n]这个样本的误差\n",
    "$lossn = x[n]^2 \\cdot w^2 - 2 \\cdot w \\cdot x[n] \\cdot y[n] + y[n]^2$\n",
    "\n",
    "假如这N个样本为一个批量，那么这N个样本的平均误差为，也叫做MES（Mean Squared Error）均方误差：\n",
    "$loss = (loss1 + loss2 + loss3 + ... + lossn) / n$\n",
    "\n",
    "那么这个批量的误差函数为：\n",
    "$loss = \\frac{w^2 \\cdot (x[1]^2 + x[2]^2 + ... + x[n]^2)}{n} - \\frac{2 \\cdot w \\cdot (x[1] \\cdot y[1] + x[2] \\cdot y[2] + ... + x[n] \\cdot y[n]}{n} + \\frac{y[1]^2 + y[2]^2 + ... + y[n]^2}{n}$\n",
    "\n",
    "那么，该误差函数关于w的导数为：\n",
    "\n",
    "$dloss = \\frac{2 \\cdot w \\cdot (x[1]^2 + x[2]^2 + ... + x[n]^2)}{n} - \\frac{2 \\cdot (x[1] \\cdot y[1] + x[2] \\cdot y[2] + ... + x[n] \\cdot y[n]}{n}$\n",
    "\n",
    "最终，该误差函数关于w的导数可以为：\n",
    "dloss = 2 * w * np.mean(x[i]^2) - 2 * np.mean(x[i] * y[i])"
   ],
   "id": "6e459b5b0a91ac2c"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## Mini-batch SGD",
   "id": "ffb14fd3a51f6a19"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "# 训练代码为\n",
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.randint(100) for i in x])\n",
    "\n",
    "print(x[:5])\n",
    "print(y[:5])\n",
    "\n",
    "x = x / 100\n",
    "y = y / 100\n",
    "\n",
    "epoch = 200\n",
    "w = 0.1\n",
    "batch_size = 10\n",
    "\n",
    "for _ in range(epoch):\n",
    "\n",
    "    # 随机打乱数据\n",
    "    # x_shuffled = x.copy()\n",
    "    # y_shuffled = y.copy()\n",
    "    # np.random.shuffle(x_shuffled)\n",
    "    # np.random.shuffle(y_shuffled)\n",
    "\n",
    "    indices = np.random.permutation(len(x))\n",
    "    x_shuffled = x[indices]\n",
    "    y_shuffled = y[indices]\n",
    "\n",
    "\n",
    "\n",
    "    # 按 batch_size 分批训练\n",
    "    for i in range(0, len(x), batch_size):\n",
    "        # 第i批\n",
    "        x_batch = x_shuffled[i:i + batch_size]\n",
    "        y_batch = y_shuffled[i:i + batch_size]\n",
    "\n",
    "        # 求批量的平均\n",
    "        x2_mean = np.mean(x_batch ** 2)\n",
    "        xy_mean = np.mean(x_batch * y_batch)\n",
    "\n",
    "        dloss = 2 * w * x2_mean - 2 * xy_mean\n",
    "\n",
    "        w = w - dloss\n",
    "\n",
    "y_predict = w * x\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, y_predict, color='r')\n",
    "plt.show()"
   ],
   "id": "55ebdc55e80d94e5"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "a = np.array([(1,1), (2,2), (3,3), (4,4), (5,5)])\n",
    "# 打乱a\n",
    "np.random.shuffle(a)\n",
    "print(a)"
   ],
   "id": "692ee4718dd6ba26"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "a = np.array([1, 2, 3, 4, 5])\n",
    "b = np.array([1, 2, 3, 4, 5])\n",
    "\n",
    "indices = np.random.permutation(len(a))\n",
    "print(indices)\n",
    "\n",
    "a_shuffled = a[indices]\n",
    "b_shuffled = b[indices]\n",
    "\n",
    "a_shuffled, b_shuffled"
   ],
   "id": "dc45714dc7121398"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "a = np.array([1, 2, 3, 4, 5])\n",
    "a1 = a[[2,3,4]]\n",
    "a1"
   ],
   "id": "6d6b691b82056564"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 扩展：多个局部最小值\n",
    "在梯度下降中，如果误差曲线存在多个局部最小值（如两个凹），判断当前是否是全局最低点通常需要结合以下方法：\n",
    "1. 梯度为零的条件\n",
    "    * 在只有一个凹的情况下，梯度为零且导数由负变正时，可以确定这是唯一的最低点\n",
    "    * 如果有多个凹，则梯度为零可能对应于多个局部最小值，此时无法仅凭梯度判断是否为全局最低点。\n",
    "2. 学习率与收敛性\n",
    "    * 梯度下降会通过不断更新参数 $ w $ 来逼近局部最小值。当梯度接近零时，算法会停止更新，认为达到了一个“最小点”。\n",
    "    * 如果初始参数 $ w $ 靠近某个局部最小值，梯度下降可能会收敛到该局部最小值，而不是全局最小值。\n",
    "3. 如何判断当前是全局最低点？\n",
    "    * 多次初始化\n",
    "        * 可以从不同的初始值出发运行梯度下降多次。如果每次都收敛到同一个点，则可能是全局最低点。\n",
    "        * 如果收敛到不同的点，则这些点可能是局部最小值，需要进一步分析。\n",
    "    * 优化策略改进\n",
    "        * 使用更高级的优化策略，如动量法 (Momentum)、自适应学习率优化 (Adam)，或者随机梯度下降 (SGD) 中加入噪声，可以帮助跳出局部最小值并寻找更低的点。\n",
    "        * 另外，可以尝试使用全局优化算法（如遗传算法、模拟退火等），它们更适合处理多凹的情况。\n"
   ],
   "id": "db2a67726e856b9"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 学习率\n",
    "学习率是梯度下降算法中的一个重要参数，它控制了每次更新参数 $ w $ 的幅度。\n",
    "\n",
    "学习率过大，会导致参数更新过大，可能错过最低点。\n",
    "\n",
    "学习率过小，会导致参数更新过小，导致模型训练速度变慢。"
   ],
   "id": "ecc76a0e32584e77"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "# 训练代码为\n",
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.randint(100) for i in x])\n",
    "\n",
    "print(x[:5])\n",
    "print(y[:5])\n",
    "\n",
    "x = x / 100\n",
    "y = y / 100\n",
    "\n",
    "# 调参 超参数\n",
    "epoch = 200\n",
    "batch_size = 10\n",
    "learning_rate = 0.1\n",
    "\n",
    "w = 0.1\n",
    "\n",
    "for _ in range(epoch):\n",
    "\n",
    "    # 随机打乱数据\n",
    "    # x_shuffled = x.copy()\n",
    "    # y_shuffled = y.copy()\n",
    "    # np.random.shuffle(x_shuffled)\n",
    "    # np.random.shuffle(y_shuffled)\n",
    "\n",
    "    indices = np.random.permutation(len(x))\n",
    "    x_shuffled = x[indices]\n",
    "    y_shuffled = y[indices]\n",
    "\n",
    "\n",
    "\n",
    "    # 按 batch_size 分批训练\n",
    "    for i in range(0, len(x), batch_size):\n",
    "        # 第i批\n",
    "        x_batch = x_shuffled[i:i + batch_size]\n",
    "        y_batch = y_shuffled[i:i + batch_size]\n",
    "\n",
    "        # 求批量的平均\n",
    "        x2_mean = np.mean(x_batch ** 2)\n",
    "        xy_mean = np.mean(x_batch * y_batch)\n",
    "\n",
    "        dloss = 2 * w * x2_mean - 2 * xy_mean\n",
    "\n",
    "        w = w - learning_rate * dloss\n",
    "\n",
    "y_predict = w * x\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, y_predict, color='r')\n",
    "plt.show()"
   ],
   "id": "5169ade2e4db2835"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 用pytorch来自动求导",
   "id": "9337ddfc89860342"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T13:00:29.864398Z",
     "start_time": "2025-06-18T13:00:29.858833Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(9., grad_fn=<AddBackward0>)\n",
      "tensor(5.)\n",
      "tensor(1.)\n",
      "tensor(10.)\n",
      "tensor(2.)\n",
      "tensor(15.)\n",
      "tensor(3.)\n"
     ]
    }
   ],
   "execution_count": 23,
   "source": [
    "import torch\n",
    "\n",
    "# 创建需要梯度的张量\n",
    "w = torch.tensor(2.0, requires_grad=True)\n",
    "b = torch.tensor(3.0, requires_grad=True)\n",
    "\n",
    "# 定义计算\n",
    "y = w ** 2 + w + b\n",
    "\n",
    "print(y)\n",
    "\n",
    "# 计算梯度\n",
    "y.backward(retain_graph=True)\n",
    "\n",
    "# 查看梯度\n",
    "print(w.grad)  # dy/dw = 2w + 1 = 5 (当x=2时)\n",
    "print(b.grad)  # dy/db = 1 (当b=3时)\n"
   ],
   "id": "df73b7833ebde2e"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T13:05:16.083751Z",
     "start_time": "2025-06-18T13:05:15.054280Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAGdCAYAAACyzRGfAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOfBJREFUeJzt3Qt4FOXZ//E7iRAOkgAiBhCBclABFU8gBKtiKlVRav9ttYpV66u2oBZ434onPMvB1yq1WqzUirYqtX1VFBUV0FI0iqJpaT0hB1EwWFAS5BAgmf91D0zcw8zuzO7saeb7ua40ZnZ2dxxp9sfz3M/9FBmGYQgAAECWFGfrjQAAABThAwAAZBXhAwAAZBXhAwAAZBXhAwAAZBXhAwAAZBXhAwAAZBXhAwAAZNU+kmeamppk/fr10q5dOykqKsr15QAAABe0Z+mWLVuka9euUlxcXFjhQ4NH9+7dc30ZAAAgBZ9++qkceOCBhRU+dMTDuviysrJcXw4AAHChvr7eHDywPscLKnxYUy0aPAgfAAAUFjclExScAgCArCJ8AACArCJ8AACArCJ8AACArCJ8AACArCJ8AACArCJ8AACArCJ8AACArMq7JmMAACB9jU2GLF39pXyxZYd0btdKBvfqKCXF+bFnGuEDAICAmf+vz+XmZ9+Tz+t2NB/rUt5Kbjyjv3x3YBfJNaZdAAAIWPD4+Z/eiQoeqrZuh3lcH881wgcAAAGaarn52ffEsHnMOqaP63m5RPgAACAglq7+Mm7EI5JGDn1cz8slwgcAAAHxxZYdvp6XKYQPAAAConO7Vr6elymsdgEAIADLaFVTkyHtW7eQzdt3iR1daFtR/s35uUL4AACgwJfRtm/Twvy+eZt96FBWh49f9dopJfV1Iu3bS64QPgAAKLBltEbM8UShw9K35S556dazvjlg5G7FCzUfAAAU+DLaRHQa5m8NS6KDR44x8gEAQACW0TqpuWlk3LG5734mnVduylnLdcIHAAAF4AuPy2OPW/tPmfP4tVHHHjrpPLl58I9F5tTktOU64QMAgALQ2cPy2DXTR8UdO+qKR+XLNuW2LddnjjkqqwGEmg8AAArA4F4dzZGKhJMkhmEbPI67fUFc8DBPz1HLdcIHAAAFoKS4yJwiUXYBZMr838iaO86IOrb0wP4y8Ib5UlufXy3XmXYBACCPmoWVJCgA1akRnSKJ7fNhN9px+C/mSH2rfUUaduddy3XCBwAAedIsrIuLAlB97Dv9K8zQ8vKy1XLD2cfGndNz0jzP15PNlutMuwAAkKNmYZ/HLJ21CkD18UR0dGToiYPigse/O3/LNnh0bNvCsVakaG/oyWbLdUY+AADIk2Zhxt4woI/r6IaGDNupmZL4sYO+//OU7CrZ02Y9di+XyacfKmMfe9f2evQ9dbQlm/0+CB8AAGSJBonZr61O2CwssgC0bvvOqKmZPhvXyoIHx8Y9p5fNaIcVJawi1XxC+AAAIEc1Hom8/F6tPPTamuYREruiUjnlFJEXX5SZNq+tIx4aPHQEZfj0RY7vEzvSkg2EDwAAcrQhXCJP16xPGDyGTlkgSyaNkJKYItTYlTPVKze5HmkZ2ns/yQbCBwAAebQhXJGIdGjbQr7culN+XDNfpr54b9w5ZlFpTGAwi1AjwoO+rwaPF5IUr+Ziqa3n1S6LFy+WM844Q7p27SpFRUXy9NNPRz1uGIbccMMN0qVLF2ndurVUVVXJihUr/LxmAAACuSFc0d7vZw3qZo52xAaP20/8adRqFqfAoCMtOtXy41lvyCPVnxT+UtutW7fKEUccIffdd5/t43fccYfcc889cv/998ubb74pbdu2lZEjR8qOHdlLVAAA5AsvIwoV5a3MJmKTzxwY95iGjllDvp80MDgt45VCXmp76qmnml92dNRjxowZcv3118vo0aPNY4888ogccMAB5gjJOeeck/4VAwBQQNyOKJx/3EFy84PXSvG18StXYnt3WEtoYwNDKlM8UuhLbVevXi21tbXmVIulvLxchgwZItXV1bbho6Ghwfyy1NfX+3lJAADkxYZw2kAsUSi49azD446d8+Mp8uZBh7sODF6meCJXxGRzR1vfO5xq8FA60hFJf7YeizV16lQzoFhf3bt39/OSAADI6w3hSpoa7ZfRGoZceO2FZkCwm5qxCwxup3h+MrSHPH7JceZqmWwHj7xY7XLNNdfIxIkTo0Y+CCAAgCDxsiFc8zLaJsNxCa3SlSyxy2rdTvGcOrBL1pbVZjx8VFRUmN83bNhgrnax6M+DBg2yfU5paan5BQBAkFlBYvZrq+XW5963DR7HXP5H2di2Q9Qy2tgltIk2pNPXTzTF41Qrkm2+Trv06tXLDCALFy6MGsnQVS9Dhw71860AACg4GiR6fLXeNnhoUakZPBJMoSTbkE67ojpN8eSquNSX8PH1119LTU2N+WUVmeo/r1271uz7MX78eLntttvkmWeekeXLl8tPfvITsyfI9773vUxcPwAAhaOoSKpGHx932G4n2tgplGQb0klEm3Sd4vFSK5L30y5vv/22nHTSSc0/W/UaF1xwgcyePVuuuuoqsxfIpZdeKps3b5bhw4fL/PnzpVWr7DUvAQAgk2x3mk02mlAU/3jvX86VxuISV1MjyVayRLZJT9RuPR94Dh8nnnii2c/DiY5+3HLLLeYXAABBk6jmwnZUYcYMkQkTPO9EWxITFNyuZLHOi60VySe+1nwAABBkyWou9PG40Q6b4CGG4XlqxO1Klmy2SS/YpbYAABTCFEtt/Q65dd6/HWsu4ramt5lm0dBh8To1kqxZWb6sZHGD8AEAgIcplmQ1F037d5aSLzfGPd7Y2CTR1R3iaWrEalamIywaNIw8XcniBtMuAADY8LpBm9IltC1igsdzB1eaq1l0l9m4aZkUm5Xl80oWN4qMRNWjOaB9QbTNel1dnZSVleX6cgAAIZ1q0bDgNXgkWkJrjUfM9CEkpLTaJo8+v5l2AQAghpcN2pxapMf27rD+pn/tU8tl+64mqShrJUf36CDLPvnKc4jI55UsbhA+AACI4XZZq13wuOT718vLfY9zfM6XW3fJhD/vadSpOaMpYv5BA8lNZ2Z/l9lso+YDAACPy1XLt2+xDR5z3/0sYfCI1RRT+KAran5mt2Q3YBj5AADAYVmr3dSL0zSLLqPtvHKTL+9/zZPLv1myG0CMfAAAEEM/9M88oou74PHFF839O6zQkm5k+GrbLnljlT9BJh8RPgAAsFlN8sw/vpn6GPHxUtvgob07ZP/943pxqHQDSLVPoyj5iPABAECC1S4aOv7wf7fYrmbR89z24vDOkKCi5gMAAIfVLra9O656trl1utOqmMjW6bV12+XW596Xr7bu9BQnhn6rkwQV4QMAgBgnXHG+rFnyStLeHYlWxUT24mjdssS2LbqT9m1ayHEF3McjGaZdAACIVFQk7ZMEDw0RXTxs4mZNxRxQ5m4qZtr3DwvsShfFyAcAABabnWh7TZqXdBM39+3Oo8c9YkdCKspK5aYzBwS+yRjhAwAAm9Ch5i9fLxUxu9pqIakGDysg2O1828XmHJ12iZ1yMfZ+v7iyp1T1r8iLPVqygY3lAADhZhc8Jk4U+dWvko5qOIWKyE3ktPA00SZ1RXsDzZJJIwo6eLCxHAAAyezeLdKiRfzxmL+TO23ipqFERzzs/gavxzRG6OPtWrVIuEmdIWI+rgGnkDeL84LwAQAIpIR1GA7TLLHBI52db61Q4bZZ2BcuN7MLAsIHACBwEtZhHNY1/glvvikyeLCn93AfFgxfNrMLEpbaAgACxarDiB2VaLNqhX3w0NEOj8HDS1jQZmGJ9nsp8rhsNwgIHwCAwHCqw9BOpQt///P4J6Sx5iLZJnJWqNBmYU77vRTZLNsNA8IHACAw7Oow7FqkH/zfT8rQKQvMUZJUJdpELjZUOO33UlHeyjwe9L4esVhqCwAIjLk16+QXc2rMfx73+p/ll3//o2On0sjlsOl8+Lvp82Fx34ys8LDUFgAQSlYdht1oR2yL9MjlsNqLI9UQELmJXLJQ4bRsN2wIHwCArMjG3/r1NW13oo3ZEM7vHhuECm8IHwCAjPMyNZGyli2lZNcu18EjrD028gEFpwCAnCx9ra3bYR5Pp+izmTYNiwken+7XzVXwCFuPjXxA+AAAZEyyFuRKH9fzUmbXrdQwpOsXn8qjFw+R9q1bOD81hD028gHhAwCQMW5bkOt5KYUOh+BhKS4uku8f1W3P6bFPD2mPjXxAzQcAIGPc1lJ4rrmwCx333y9y2WWONSb6lMjmEhV+15zANcIHACBj3NZSuK65qKsTad8+/nhEqnDa5t6a2bm4sqdU9a8IVI+NQsO0CwAgY9y2IHdVc6FDF0mCR6IaE+v9nv9XLcEjxwgfAICM8dKC3PM0yyefxO3NktEaE/iG8AEAyKi09jV58UXnotKDDspejQl8Rc0HACDjvLQgb2YXOlSCLcl8rzFBRhA+AABZ4akFuV3waGpyDiQxNSbawMwuohTtHXGhr0duMe0CAMgfP/yh8zRLkuDha40JMorwAQDIDxou/vpXT9MsvteYICuYdgEA5F6CTqWp7IabUo0JsobwAQDInSRFpenshss29/mLaRcAQP4EjzFjooJHxnfDRU4w8gEAyC5dtVJSknKnUj2msUUf16kVplIKDyMfAIDsjnYkCR6KTqXBRvgAAORummXhwrgRj+qVm+QFl1MqdCotTEy7AAAywlql8vV7H8h3zhyedLTDrrg0GTqVFibCBwDAd1aQqL62yv4Em+ChRaRuO3rQqbSwMe0CAPCVFSTsgsfA8U/I/OXro44lKi61Q6fSwkf4AAD4RoPEmv++XlZPHxX3WM9J82RraRszaOh5botLY9GptPAx7QIA8CRRx9GSkmL5mc1zNHjErlKxGoC5LRr9ydAecurALnQqDQDCBwDAtYQdRw/r6hg6YkUGDrdFoxo86FgaDL5PuzQ2NsrkyZOlV69e0rp1a+ndu7fceuutYnjcGAgAkF+cOo4uvn6kp+ARGzh0JEMDjNNYhh7XxykuDQ7fRz6mT58uM2fOlIcfflgGDBggb7/9tlx00UVSXl4uV155pd9vBwDIAqei0DU2tR2ql0PwsFulolMoOnKiwUYfj3wPikuDyfeRj9dff11Gjx4tp59+uvTs2VN+8IMfyCmnnCJLly71+60AAFliVxRqFzyqP97YvJolNiokChJaPKpFpBpMIlFcGky+j3wMGzZMHnjgAfnoo4+kX79+8o9//EOWLFkid911l99vBQBIk9vt6iNrNJxGO3Sa5ddbdsjoQd3MwBBbG1KRZDdaPa57tbi5HhQ238PH1VdfLfX19XLIIYdISUmJWQNy++23y3nnnWd7fkNDg/ll0ecCADLPy3b1Vo2GXfD49bAfy93Hnxd1XqpBQh+nqDT4fA8fTzzxhDz66KPy2GOPmTUfNTU1Mn78eOnatatccMEFcedPnTpVbr75Zr8vAwCQgFNHUWu7+tipjsH7t7QNHlZRqVMtB0ECdooMn5ehdO/e3Rz9GDduXPOx2267Tf70pz/JBx984GrkQ1+jrq5OysrK/Lw0AMDeqZbh0xc5NvaygsSSSSP2jFTYbQgXEzwUtRnhVl9fby4ucfP57fvIx7Zt26S4OLqOVadfmpqabM8vLS01vwAA2eFlu/qhfTrFPX7elbPktdZdXNdyABkPH2eccYZZ43HQQQeZ0y7vvvuuWWz605/+1O+3AgCkwE1H0W+vWiZD+9gUlhqGPOKySBXIWvj4zW9+YzYZGzt2rHzxxRdmrcdll10mN9xwg99vBQBIQbKOok6rWaydaKnlQN7VfGRzzggAkHrNhxaXumoatnu3zp9n6/JQoLx8frOrLQCEKHRUr9wk8/65Xs45trsZPKzJkkf+PNk+eOjfTwke8BkbywFASHt6tG/Twvxec+NI+yfl18A4AoTwAQAh7elRt22XrHYa7QAyiPABAAHmdUO4xsYmWbpyEytZkFGEDwAIMLcbwu08oEIWLXhHbo5pPubUbh1IBwWnABCWnh6G4dgifdqsBebUTGxQsdqt69QN4BdGPgAgwDq1LU26E616umZ93NSMslbE6NSNbhTHFAz8wMgHAARZkX3w+OWpVzYHD/Xl1p2u2q0DfmDkAwCCasUKqezXL+5wZOjwuy074AbhAwCCKMlOtJloyw64RfgAgBAEj2PH/VH+s2+H+FNF5IAyrQspkg318e3WrXN051pddgv4gZoPAAgK3cDTJnjMX75eNu7bobmVusX6+aYzB8hNZ/aPOhZ7ji63pdgUfiF8AEAQaOi49db444Zh9uiYOeYoc/Qikv6sx/VxN+cAfmFXWwAIYn2Hza927XaqK1YSdS91cw6Q7uc3NR8AELCiUqe9WTREDO29X8KXdHMOkC6mXQAgBMEDyCeMfABAoXE5zQLkK8IHAARwtIPaDeQzwgcAFGrwOO00keeeizusm8DpXizsTot8Rc0HAOSz7dudp1kcgge70yLfET4AwAc6zVG9cpPMrVlnftef06aho00b1/Ud+p464uG0O63Sx325NiANTLsAQJoyMs1hN9qxcKHIiBGOT9Eaj9gRD6fdaVlOi1xi5AMA0uD7NMdLLzlPsyQIHl52nWV3WuQaIx8AkKJk0xwaIfTx7/SvcLfSJM3eHW53nWV3WuQaIx8AkCIv0xwpBY8dOzz179DltDrd4xRz9Lg+zu60yDXCBwCkyJdpjpNPdp5mKdWt7t3T0RWtM1HsTot8RvgAgBRXtqzY8HV60xwaOhYt8rVbKbvTohBQ8wEAaa5scVK090Pfdpojgy3SNWBonQkdTpGvCB8A4HFli5uI4DjNkaUN4didFvmM8AEACVh7pNTW75Bb5/3bVfCQvSMecX0+2IkWMBE+AMBhQ7Y1G7fJ40vXmsHDrctP6i2VffaPn+ZwOc3ChnAIA8IHAKRQz+Gk7wHtoqc7PIx2sCEcwoLVLgCQoFOpV1ErW2yCx9oJ18jcdz+L2/+FDeEQJox8AAi9RJ1K3Ypa2fLZZyLdu8edM3TKgj3hYk5N1KiGrkzxtVMqkOcY+QAQesk6lXpa2VJSbBs8ek2a5ziqce+iFf51SgUKACMfAELLKu58Ic0pjeaVLYd1jX+PFR/L8L+sEcMmXFijGg+9tsbV+7AhHIKC8AEglNIpLtXA0LFtS7n+9EOlory1DJlzvxQfVhV/omHI0pWbko5qbN6+y9X7siEcgoLwASB0vDQLc5piuf2sgXtWoCRZzeJ2tKJ96xZSt32X7TUl7JQKFCBqPgCESrrFpVF7pNgFj6amqGW0bkcrLqrsZX5nQziEASMfAEIlneJSbSA24TsH7ykqtRMROiI7o3Zs20K+3Go/tWKNalw+oo8cXLFv3FSQbadUoMARPgCESjpFm0N7d3IVPNzWk8SOarAhHMKC8AEgVNIp2qzsu3/STqVe6knsRjXYEA5hQPgAECo6kqDNvbTHhtu6jzXTR9k/EBM8ktWTxK6SYVQDYUXBKYBQ0Q97HW1QRakGj379bPdmSVZPos/YtHWnGTx0dIPggbAifAAIHZ3m0BUrOu3hZJ/G3fbBQ0PHhx+mVU9CszCEHdMuAEIptrhzzcatcveCFeZoyGqX0yyp1pPQLAxhR/gAEFqxxZ0HV7SzbZH+7p2/kyP/+9K4ZbSxK1KS1ZPQLAzYg/ABIK84fbBn3CuvyHdHjIi/nsYmOTLi/e2W0Vq70+poin7X1S76jMgAQrMw4BuEDwB5I9kHe8YCikOL9OqPN8pgF8tord1prc6n+p1mYYCzIsNIMomZZfX19VJeXi51dXVSVlaW68sBkCVOH+xWLLA+2N0GlHSCx4DxT8jW0jZRr631IcOnL3JczWJNqSyZNMIMQjkbwQEK4POb1S4Aci5RfwzrmD7+/D/XmwElNgBYIw8aTFw7+WTb4NFz0rzm4BH52vcu+jjpMlp9XANHZD3J6EHdWFYLxCB8AMg5N/0x9PFJTy5PGlA0yCSloWPRItvg4fTaD72+OvnrsowWcIXwASDn3H5gb9mx2/XIgx0zmNiMdmhth13wiHztzdvsN4aLxTJaIEfhY926dTJmzBjZb7/9pHXr1nLYYYfJ22+/nYm3AhAAnfYtzXyQKSqy3RRu/vL1rsNP+9YtHLuiFu2tD2EZLZCD8PHVV19JZWWltGjRQl544QV577335Fe/+pV06NDB77cCEBQ+lr3bjjw4rGbpNWmeWc+hDcbcuKiy556Xi335vd9ZRgvkaKnt9OnTpXv37vLQQw81H+vVq5ffbwMgz3lZ7bFxa0Pa7+fYwMuhqDTyeY8vXSsVZa1kQ33i5mCXj+hrNiJjGS2QZ+HjmWeekZEjR8oPf/hD+dvf/ibdunWTsWPHyiWXXGJ7fkNDg/kVuVQHQGHzuhw23ToJ25EHh9GO2NoODRu19Q0yoaqfzFjwUdLmYLFt2VlGC+TBtMuqVatk5syZ0rdvX3nxxRfl5z//uVx55ZXy8MMP254/depUc12w9aWjJgAKv1+Hl+WwVlvyVD++deTB6gPiFDzmHH5KwqLSnp3a2G42F/faLKMF8q/JWMuWLeWYY46R119/vfmYho+33npLqqurXY18aAChyRhQmFMtXhpx2YUW5eaXUse2LWTyqAHmdMnRPTrIsk++ks2frJNTTz4i7txEocPy+CXHmUGC5mBAATYZ69Kli/Tv3z/q2KGHHipr1661Pb+0tNS8yMgvAMHu12G3HNbNNveqaO/XlLMOk7OO7CZ123fKCf/7igzt08k2eOjeLIlGVWJXqTCqAWSe7+FDV7p8+OGHUcc++ugj6dGjh99vBSDPuF2y6nSeBhAdFdFRiF+fM0gmVPWVirJSx2kQa7Sk+tqq+Nf66b3mMloND1qvoVilAgS04HTChAkybNgwmTJlivzoRz+SpUuXygMPPGB+AQg2t4Wjic6L3eZeV5jYTYPo9Mg/r5smq5+5x3aaRaOEFr1qcSibvQEh2Fhu3rx5cs0118iKFSvMZbYTJ050XO0Si43lgMKv+dDiUsNjzYdnLlezWLUc1vVRzwFkhpfPb99HPtSoUaPMLwDhYk1x6FRIsiWrabHr3XHVs7bHI6d4YkdVAOQGe7sA8ExHEKpXbpK5NevM75GbuTkVjtotWfVs332dm4Y5jISw1wqQfzIy8gEg3A3EMtKIK0GLdE8dTwHkHCMfADLSQMyvJatOO9GKYZirWRSrWIDCQvgA4DoE6IiHXSGpdUwfj5yCSVuCnWgzPsUDIGOYdgHgewMxu6JOzytNbEY7vmrVTo76xeMif3qnOVyw1wpQeAgfADLeQMzTRnNNTSIlJUl3orV6eGjIYBULUFiYdgGQ0QZinjaa09GOJMEjWZt2APmP8AHA1bLa2rrt0rFtS9d7pHiuE7GZZhk/6r8TbgrndjQGQH5h2gWAI7vpEjtOq0vc1Im0X/GelJRUpbQTLT08gMJE+ABgy5oucbN2xW6PFB3NeO3j/yR83prp9p2QzZ1oXbRpp4cHUJgIHwDiJJousXRs20ImjxogFWXxq0vcjJjYBo9Nm0Q6dhSt+shKm3YAOUHNB4A4yaZL1Jdbd5nBI7aBmFOBqWXaC/fYBw/d47LjNyMZ9PAAgouRDwC+LatNNmLiNM1iBg8b9PAAgonwAcC3ZbWJRkzsgod2Kk02gkEPDyB4CB8A4ujogi6b9VrwaTdikqio9LuMYAChRM0HANvRBi3o9LppW+xIiFPwqP54I1MnQIgRPoAQsxqIza1ZZ36P3BQulYJPa8SkyCF4aO+OQTe/KE1Nhr8b0AEoKEWG4VDplSP19fVSXl4udXV1UlZWluvLAQLL7X4rfmwIZ9c0zHFvFwAFycvnN+EDCCGnBmJWbEi2lNUxkNgEj9d6HC7nnTMl7rjb9wJQGLx8flNwCoRMsv1WYneMdTNi0qd0tyy45XueWqS7eS8AwUT4AELGzX4r1o6xsUtc7UZMnIpK3ezNkui9AAQX4QMIGT8biNkFjx+eO03e6j4wI9cEIBgIH0DI+NFA7P8tXyi/ev7ulEY70rkmAMFA+ADynOfVJklep7Z+h7kpnO7N4qR9mxbNy2Gt97JGJ5JNs7RpWSLbdja6uiZ2pwXCifABBGA5bCqvk8jmbbvkvAffjHovDT52waP3L+dKY7HuQ7tHscNS21jsTguEF03GgDzltDustjzX4/p4Oq/jhvVeDfvtL0P7dLId7bCCh8YHHVH5umG3q9dmd1ogvAgfQAEuh1X6eLIuocl2md0TGFpKeSv7QVB93urpo6T0y40J6zuscYuzBnUTNy4/qY8smTSC4AGEFOEDKPDlsOm+zpdbd0rdjt2edqIdOmWB7ShGVf8KcaOyTyemWoAQo+YDCNBy2FRfJ5ZTUakYhnxXxGwKZlcEqyMtqeyGCyBcGPkAArQcNtXXcbsTrUWDhjYFGz2om/ndGsVIdTdcAOFC+ADyUOTusHb0eBcXIwhuX6eirFQ3erINHr0mzTOnWdyOVqSyGy6AcGFjOSBPWatUlJHGhmyuXuewrrbP1eChz5lQ1Vd6dmrrqc+IX/1JABQGdrUFAiKTfT6aX8cmeNx5/Bi5d9g5ZrMxq+9HOu8PIPjqCR9AcPjd4bT5dXZskJKBA2xrO/ScNRu3yYwFH8UVjnodeQEQDvUePr9Z7QLkOau404/Q0vw6Dl1Itbbjxu07ZdThXWX49EWOfUb02TqSoqtemEoB4BXhAwjgyIfXaZYhY2fLhnadpGhvR9PxVX1d9xlJJRgBCDfCBxCwmg+rwDR21GLMM7+T7177l4SdSq1RjYdeW+Pq+lLtIwIg3AgfQJ5yChHWfit2NRdO7dST7UQbSZ+7ebvzjrfp9hEBAMIHUIB7uzjVXNi1U7cLHnahI1b71i2kbvsuOpUC8B1NxoAA7e0SOQ2ioSPV4KEuquxlfqdTKQC/ET6AAO3tYk2DJJtm0Z1sk3U9vXxEHzqVAsgIpl2AAO3totMgyUY7dDrlJ8f1kBkLV5hBw0gwqqEBw2kTOQBIFeEDyEPWniyedoctKpISm3Njp1m0mFSDh1330gqblTSp9hkBACeEDyAPu5Jau8PqqpZkoxN7Dsa/9quHVsqFZ17j+B51e0PHhKp+0rNTG0Y1AGQN4QPI0/1YrN1hY18ranRixw6R1q3jr2H5ernpmfdE6hMXrWrMmPPWWlkyaQShA0DWsLcLkIXeHOnsh+I4iuLQIl2Dh901JPL4JccxtQIga5/frHYBstSbQ+njep4XVs3F6EHdzO+OweOVV6SxscnxGhKhUymAbCJ8ADnuzRFJg0n1yk0yt2ad+T0uqCxcaB88dADzxBOTXoMTOpUCyCZqPoAc9+ZwXSviMM1iBg+P12ChUymAXGDkA8hxb47IWpHYUQtrHxfb4KHFpjElW15GMOhUCiBXCB+Az705knUOjR1lSFQr8tunpshqu26lGjpKSz1fQyQ6lQLIFaZdAJ947s2xl1OdhlOL9NjRDrfXYLm4sqdU9a+gpweA4I58TJs2TYqKimT8+PGZfisg56zeHF72Q7Gr07ALHnPf/Sxh8Eh2DToicv+Yo2TyGQO+WTUDAEEb+Xjrrbfkd7/7nRx++OGZfBsgr3jdDyWyTiPRhnCPe6jnYE8WAKEMH19//bWcd955MmvWLLntttsy9TZAXvKyH4pVp1F9bVXcY01SJL0nPWtbK+LnNQBAIKZdxo0bJ6effrpUVcX/Qo3U0NBgdkWL/ALCREOCXfDQ0Q4NHooVKQCCJCMjH3PmzJF33nnHnHZJZurUqXLzzTdn4jKA/OfQu8PaidZul1kAKHS+h49PP/1UfvGLX8jLL78srVoln6O+5pprZOLEic0/68hH9+7d/b4soCCCR9OMGfLmqDHya+o0AASY7xvLPf3003LWWWdJSUlJ87HGxkZzxUtxcbE5zRL5WCw2lkPg1daKdLEZycivPR4BwBMvn9++j3ycfPLJsnz58qhjF110kRxyyCEyadKkhMEDCDwXLdIBIOh8Dx/t2rWTgQMHRh1r27at7LfffnHHAQl78PjkE5GDDsrF1QBAztBeHci0Bx903omW4AEghLLSXv3VV1/NxtsA+YdpFgCIw8gHkM3g0dRE8AAQemwsh9DS3WQz0n68Xz+RFSvijxM6AMBE+EAozf/X5+Y29pG7yWoL88mnHyod2pamHkiYZgGApAgfCGXw0C3nY+OABpGxj70bdayLlw6jTkWlAIAo1HwgdFMtOuLhNhLU1u0wg4oGloShg+ABAK4RPhCq4DH7tdVRUy3JWPFBA4s+P45d6PjBDwgeAJAA0y4IbY2HWxoj9HlanNq8Rf3u3SItWticTOgAgGQIHwhtjYdXWoRqoqgUANLCtAsCzWuNRyK6+sU2eCxYQPAAAA8Y+UCg6VRJKlMtkTRuVG5fL0P7dIp/kNABAJ4RPhBozVMlaQSP1dNH2T42993PpPPKTf41JwOAkCB8INDMqZI02AWPE2+aJ2u2i8icGu+9QAAA1Hwg2HRUQsOBm3EJPe+35x4pj19ynLz0xQuyxiZ49Jq0N3h47QUCAGjGyAcCTadDdFRCw4EGELsKjYsre0pV/4pvpk8cVrMMnbJADJv6EX1NfYYWtn6nfwVTMACQBCMfCDydDpk55iipKI+egqkoK5UJVX3l8O7tvzno0Km0+uONCQtXI3uBAAASY+QDoQkgOiph7WK7ZuM2eXzpWrl7wZ7dZ+2mWCJXs7gtXE23wBUAwoCRD4SGTodoh9LSfYplxoKPpLZ+h3PwOOCAqGW0bgtX0y1wBYAwIHwg75uEVa/cJHNr1pnfbfdXSaPpmF3w0NqOxvWfeypc1eP6uJ4HAEiMaRcU1H4s6S5rtZqOOU2z9Jw0TyR2H5ckhatWINHHKTYFgOQY+UBe78cSW+SZ7rJWs97DJnjcdPKle4JHxHmuC1fLW5nH6fMBAO4w8oGC2o8lrWWtW7bI6CMPjDscGTqS1W7EFq7qeXQ4BQBvCB8ouP1YbLe4T8ahd0ds8CjaO5KRqHbDKlwFAKSG8IG848eyVh09sUYn7EY7hv58ttSWRW8UR+0GAGQHNR/IKxoaNm5pcHWu09SI1oMMn75I7rn+d7bBQ5fQ3jj2FGo3ACBHGPlAXq9usZNoasQqVHXaiXb+8vXyXWo3ACCnCB/ImcipEe04qo2/knXxSDQ1YhWq2gWPnlc9K0VFRVIRUahK7QYA5AbhAzkKG1vN9ua19e6mWCwVCfp8/Of8n0r1Y7Mdi0pTKlQFAPiO8IG8mlJJZPLph8qFlb3sp0Z0VMPmOXbLaNl/BQByi/CBjLPqMNJrjC7SqV2pY/BwEzos7L8CALlF+EDOGoZ5FRcaHHp39HIIHm56eAAAMo+ltshpwzA3bDdtswse48aZq1ms58S+hqKHBwDkHiMfyChr2/pUxYUG3ea+2CYz63FdQiti9uqIrS9JVKgKAMguwgcy6suvva1miRUVGhymWazgYaGHBwDkN8IHMqpj25auz7W2qp9Q1Vd6dmobHRrsgsfixSLHH2/7WvTwAID8RfhARlWUt/Zwrs3UyKefihx0UNLRDgBA4SB8IKN05EKLRRMVnbZv00Lu+/FRclzv/aKnRlxOswAACgurXUK+DLZ65SaZW7PO/K4/+03DhI5mOFVb6PFp3z9MKvt2Sh48tmwheABAADDyEcLW5lpL8dXWnXLrc9ErQrpkaEWIvp7dChTb93v0UZExY+JfhNABAIFRZBj59Vu9vr5eysvLpa6uTsrKynJ9OaHbLVZlalv52AAUtwKFaRYAKFhePr8Z+Qg4L63N9Rz9+L85YudXPyVcgWIXPAgdABBI1HwEWCqtzSN3fs2KqiqCBwCEDCMfAZZOa/Os7PxqFzqOPVZk6dLMvzcAIGcIHwGWToDI+M6vjHYAQGgRPgIslQCR8Z1fKSoFgNCj5iMEDb7clo1mfOdXu+DxyCMEDwAIGcJHgFkNvpSbKKEjHhlZZtvQ4DzNcv75/r4XACDvMe0ScIkafE0+/VDp0LY0szu/Ms0CAIhB+AiBnG0xbxc81q0T6do1s+8LAMhrhI+AsusmmrUt5j/4QOTQQ+OPM9oBACB8hKedutt9W5K2QE+GaRYAQBKEj5C0U6+t22EeT1RQmk5ocQwejY0ixdQ1AwC+wadCSNqpW8f0cT3POr965SaZW7NOfr1ghRlOYjuiWqFFg4mjWbOcV7MQPAAAmR75mDp1qjz55JPywQcfSOvWrWXYsGEyffp0Ofjgg/1+K3hspx65b0vd9p2udrpNutmcXejo0UNkzZqU/z0AAMHm+19L//a3v8m4cePkjTfekJdffll27dolp5xyimzdutXvt0KK7dQXvFdrO8rhebM5p9EOggcAIJsjH/Pnz4/6efbs2dK5c2dZtmyZfPvb3/b77QLPSwGo23bqT9Ws87TTbVy4OeEEkcWL40+gqBQAkA8Fp3V1deb3jh0ztFdIgHktALXaqWudhl0M0MjSsW1L2bR1Z0rXY4Ybu9GOW24RmTw5pdcEAIRPRqsBm5qaZPz48VJZWSkDBw60PaehoUHq6+ujvvDNqhUvBaCJ2qlbP48e5L3Blz63S1mpDO3TyX60g+ABAMiX8KG1H//6179kzpw5CQtUy8vLm7+6d+8uYed11YpdO3Xdp8Vu3xYtGvUaPFZPHyXV133H5mKYZgEAeFdkGJn5BLn88stl7ty5snjxYunVq5fjeTryoV8WHfnQAKLTNWVlZRJGuvz1x7PeSHre45cc59i11KlWRI8Pn77IcWom1prpo+IPvvmmyODBbv5VAAAhUV9fbw4iuPn89r3mQ7PMFVdcIU899ZS8+uqrCYOHKi0tNb/gfdVKovM0aNgFE2tqRqdudFQjMoBYP0+o6it9W+6S006wmSpjtAMAkKZ9MjHV8thjj5mjHu3atZPa2lrzuKYh7fuB5NyuWnF7ntudbiusYtbDHOpCCB4AgHycdily2NvjoYcekgsvvNDXYZugSjY1UrQ3KCyZNCKtnWltp2ZKbMqAtmwR2XfflN8HABB89bmedkF6kk2NKH08neARNzXz+usifSrjT+K/JwDAZ2y8kaeSrVpxtdGbWzpaVUnwAABkB7va5jENGLo0Nq0t7pNxapEOAECGED5y3BI9GadVK2mbOVNk7Nj44wQPAECGET5y3BI9JwHIbrRjzBiRP/4xa9cHAAgvwkcGWqLHjh1YLdF9r9VIJQDZLaNltAMAkEUUnOZBS/Rs7Alz+++vJngAAPIC4cMnOsUR+4EfST/i9XE9L9sBSFukj1j1dvTBl14ieAAAcoJplzxqie53ACpuapRV/zs67rzqjzdmpogVAAAXCB8+rVzJdEt0r8Hm1d9dIj03fx53Ts9J8+TXGQxAAAAkQ/jwaeXK0T06iGaSRCUd+rielylWsLHbifbYcX+U/+zbIeMBCACAZKj58Fi4aa1c0ccjLfvkq4TBQ+njel6mDC4zbIOHjnZo8CjaG5509AYAgFwhfPi0ciXnNR9FRVLSef+oQ+/v39MMHubDPu4JAwBAOph2SXPlilW4mdOaD5umYZW3vSjrtuyK2hMm243OAACwQ/iwkcoohk5l6JSGTsvYjZgU7Q0Avk55LFsmcswx8ccNQxb72OIdAAA/Me1iI5VRDP1g15GFRHyd8tDRjtjgcfXVzb07rD1hRg/qZn4neAAA8gUjHzZSHcXQKY1Lv91LZv19dVTxqX7uX3J8L/+mPNiJFgBQwBj5sBE5ihH7MZ+ocFNXwDywODp4WLlAj8eukPFs1iyCBwCg4BE+HOgohW4EpyMckfRnuw3iMr63i4aOSy+NPvbsswQPAEDBYdolAQ0Y3+lf4apwM5UVMq4x2gEACBDCRxJW4WYyGenzMXGiyN13xx8neAAAChjhwye+9/mwG+34+GOR3r09XhkAAPmF8OET3/p8NDSItLIJKIx2AAACgoLTHK+QiTJgQHzw6NWL4AEACBTCRw5XyMRNs7z3XvSxbdtEVq3K0NUCAJAbTLt4pEtlE61+8bJCxrRunciBB8YfZ7QDABBQhA8PtEmY9uqIXFLbxWbDNrcrZGyLSi+7TOT++327ZgAA8g3hw0Pw+Pmf3okrJtUCUz2edFrFTfBoarI/DgBAgFDz4YKv3Uv//nfnpmEEDwBACBA+XPDSvTQhDRff/nb0sYcfpr4DABAqTLu44Ev3UlqkAwBgYuTDhU77lqZ+3j33EDwAAIjAyIcbRorn2YWOd94ROfJIP64KAICCRPhwYePWBm/n6ahGsc2gEqMdAACEZ9pFV6JUr9wkc2vWmd9drUxJZdO4u+4ieAAAEPaRD7fNwdLdNG5on07xD27eLFJenu6/AgAAgVEcluZgsUtlreZg+ni6m8aV7mqQ6mur7Ec7CB4AAIQnfPjZHMxp07j7598lH9z1/6JPvukmplkAAAjjtIuX5mBu9mKJ3TRu9JE2G8I1NtrXfAAAgOCHD1+ag8UwN41rtUOkDzvRAgCQikD/Fd3TKhW37r5b5MCY4PHXvxI8AABwKdAjH25Xqeh5rtCpFACAtAV65CPZKhWlj+t5Ca1bFx88JkwgeAAAkIJAh49Eq1T0Zz2etM/HX/4SP83y+ed7mokBAADPAj3t4rRKRWs8dKol6YjHqaeKzJ8ffYzRDgAA0hKK8NG8SsXFclrThg0iFRXRx/7v/0S+//2MXBsAAGESmvDh2iOPiFxwwTc/a63Hjh0iLVvm8qoAAAiMwNd8uKbTKQMGRAePW24RaWoieAAA4CNGPtSqVSK9e0cfe/99kUMOydUVAQAQWIx83HlndPDo0WNPi3SCBwAAGRHekY/du0U6dhTZsuWbY/ffL3LZZbm8KgAAAi+c4aOmRuTII6OPffaZSLduuboiAABCI3zTLv/zP9HBY/jwPUWlBA8AALIiXCMf2rtDe3hY6N0BAEBwRj7uu+8+6dmzp7Rq1UqGDBkiS5culZyqr48OHl9+SfAAACAo4ePPf/6zTJw4UW688UZ555135IgjjpCRI0fKF198ITlTVibyxBMiDz+8p6dHhw65uxYAAEKsyDD836xERzqOPfZYuffee82fm5qapHv37nLFFVfI1VdfnfC59fX1Ul5eLnV1dVKmgQEAAOQ9L5/fvo987Ny5U5YtWyZVVVXfvElxsflzdXV13PkNDQ3mBUd+AQCA4PI9fGzcuFEaGxvlgAMOiDquP9fW1sadP3XqVDMpWV86QgIAAIIr50ttr7nmGnOIxvr69NNPc31JAACgkJbadurUSUpKSmRD5MoSc5f6DVIRu029iJSWlppfAAAgHHwf+WjZsqUcffTRsnDhwuZjWnCqPw8dOtTvtwMAAAUmI03GdJntBRdcIMccc4wMHjxYZsyYIVu3bpWLLrooE28HAADCHj7OPvts+c9//iM33HCDWWQ6aNAgmT9/flwRKgAACJ+M9PlIB30+AAAoPDnt8wEAAJAI4QMAAGQV4QMAAGQV4QMAAGQV4QMAABT+Utt0WItv2GAOAIDCYX1uu1lEm3fhY8uWLeZ3NpgDAKDw6Oe4LrktqD4f2op9/fr10q5dOykqKkorgWmA0Y3q6BeSedzv7OJ+Zxf3O7u434V5vzVOaPDo2rWrFBcXF9bIh17wgQce6Nvr6Y3kD2/2cL+zi/udXdzv7OJ+F979TjbiYaHgFAAAZBXhAwAAZFVgw0dpaanceOON5ndkHvc7u7jf2cX9zi7ud/Dvd94VnAIAgGAL7MgHAADIT4QPAACQVYQPAACQVYQPAACQVQUdPu677z7p2bOntGrVSoYMGSJLly5NeP5f/vIXOeSQQ8zzDzvsMHn++eezdq1B4OV+z5o1S44//njp0KGD+VVVVZX0vw/S+/NtmTNnjtkd+Hvf+17GrzHM93vz5s0ybtw46dKli7lKoF+/fvxOyeD9njFjhhx88MHSunVrsxvnhAkTZMeOHVm73kK2ePFiOeOMM8zOo/q74emnn076nFdffVWOOuoo8892nz59ZPbs2f5elFGg5syZY7Rs2dL4wx/+YPz73/82LrnkEqN9+/bGhg0bbM9/7bXXjJKSEuOOO+4w3nvvPeP66683WrRoYSxfvjzr1x6G+33uueca9913n/Huu+8a77//vnHhhRca5eXlxmeffZb1aw/D/basXr3a6Natm3H88ccbo0ePztr1hu1+NzQ0GMccc4xx2mmnGUuWLDHv+6uvvmrU1NRk/drDcL8fffRRo7S01Pyu9/rFF180unTpYkyYMCHr116Inn/+eeO6664znnzySV3dajz11FMJz1+1apXRpk0bY+LEiebn5W9+8xvz83P+/Pm+XVPBho/Bgwcb48aNa/65sbHR6Nq1qzF16lTb83/0ox8Zp59+etSxIUOGGJdddlnGrzUIvN7vWLt37zbatWtnPPzwwxm8ynDfb73Hw4YNM37/+98bF1xwAeEjg/d75syZxre+9S1j586dWbzK8N5vPXfEiBFRx/SDsbKyMuPXGjTiInxcddVVxoABA6KOnX322cbIkSN9u46CnHbZuXOnLFu2zBzKj9wTRn+urq62fY4ejzxfjRw50vF8pHe/Y23btk127dolHTt2zOCVhvt+33LLLdK5c2e5+OKLs3Sl4b3fzzzzjAwdOtScdjnggANk4MCBMmXKFGlsbMzilYfnfg8bNsx8jjU1s2rVKnOK67TTTsvadYdJdRY+L/NuYzk3Nm7caP6fXP9PH0l//uCDD2yfU1tba3u+Hof/9zvWpEmTzPnG2D/Q8Od+L1myRB588EGpqanJ0lWG+37rh9+iRYvkvPPOMz8EP/74Yxk7dqwZsLVTJPy93+eee675vOHDh5s7p+7evVt+9rOfybXXXpulqw6XWofPS939dvv27WbdTboKcuQDhWXatGlmEeRTTz1lFpfBX7qF9fnnn28W+Xbq1CnXlxMKTU1N5ijTAw88IEcffbScffbZct1118n999+f60sLJC1+1JGl3/72t/LOO+/Ik08+Kc8995zceuutub40hGnkQ3/BlpSUyIYNG6KO688VFRW2z9HjXs5Hevfbcuedd5rhY8GCBXL44Ydn+ErDeb9Xrlwpa9asMavZIz8c1T777CMffvih9O7dOwtXHp4/37rCpUWLFubzLIceeqj5N0adVmjZsmXGrztM93vy5MlmwP6v//ov82ddrbh161a59NJLzdCn0zbwj9PnZVlZmS+jHqog/4vp/7H1bxsLFy6M+mWrP+s8rB09Hnm+evnllx3PR3r3W91xxx3m30zmz58vxxxzTJauNnz3W5ePL1++3Jxysb7OPPNMOemkk8x/1mWJ8PfPd2VlpTnVYoU89dFHH5mhhODh//3WmrHYgGEFP7Yn819WPi+NAl6qpUuvZs+ebS4FuvTSS82lWrW1tebj559/vnH11VdHLbXdZ599jDvvvNNc+nnjjTey1DaD93vatGnmUrq//vWvxueff978tWXLlhz+WwT3fsditUtm7/fatWvN1VuXX3658eGHHxrz5s0zOnfubNx22205/LcI7v3W39d6vx9//HFzGehLL71k9O7d21zFiOT09662PdAv/di/6667zH/+5JNPzMf1Xus9j11q+8tf/tL8vNS2CSy1jaBrjw866CDzQ06Xbr3xxhvNj51wwgnmL+BITzzxhNGvXz/zfF1G9Nxzz+XgqsNxv3v06GH+IY/90l8iyMyf70iEj8zf79dff91crq8forrs9vbbbzeXO8P/+71r1y7jpptuMgNHq1atjO7duxtjx441vvrqqxxdfWF55ZVXbH8fW/dYv+s9j33OoEGDzP8++uf7oYce8vWaivR//BtHAQAACGDNBwAAKFyEDwAAkFWEDwAAkFWEDwAAkFWEDwAAkFWEDwAAkFWEDwAAkFWEDwAAkFWEDwAAkFWEDwAAkFWEDwAAkFWEDwAAINn0/wHPk1Ijh0LPSQAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最终拟合的权重 w: 10.688233375549316\n"
     ]
    }
   ],
   "execution_count": 26,
   "source": [
    "import torch\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 数据准备\n",
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.rand() * 100 for i in x])\n",
    "\n",
    "# 将数据归一化到 [0,1] 范围内\n",
    "x = x / 100.0\n",
    "y = y / 100.0\n",
    "\n",
    "# 将 NumPy 数组转换为 PyTorch 张量\n",
    "x_tensor = torch.tensor(x, dtype=torch.float32)\n",
    "y_tensor = torch.tensor(y, dtype=torch.float32)\n",
    "\n",
    "# 初始化模型参数 w 为可学习的 Parameter，设置 requires_grad=True，表示w参数需要求导，需要计算梯度\n",
    "w = torch.nn.Parameter(torch.tensor(0.1, dtype=torch.float32), requires_grad=True)\n",
    "\n",
    "# 定义优化器 (SGD - 随机梯度下降)\n",
    "optimizer = torch.optim.SGD([w], lr=0.01)  # learning_rate = 0.01   # w = w - lr*w.grad\n",
    "\n",
    "# 训练循环\n",
    "epochs = 200\n",
    "for _ in range(epochs):\n",
    "    # 遍历每个样本\n",
    "    for i in range(len(x_tensor)):\n",
    "\n",
    "        # 前向传播: 计算预测值\n",
    "        y_predict = w * x_tensor[i]\n",
    "\n",
    "        # 损失函数: 平方误差\n",
    "        loss = (y_predict - y_tensor[i]) ** 2\n",
    "\n",
    "        loss.backward()     # 反向传播\n",
    "        optimizer.step()  # 更新参数w的值\n",
    "        optimizer.zero_grad()  # 清除w之前的梯度\n",
    "\n",
    "# 最终预测结果\n",
    "final_prediction = w.data.item() * x_tensor\n",
    "\n",
    "# 绘图\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, final_prediction.numpy(), color='r')\n",
    "plt.show()\n",
    "\n",
    "# 输出最终的权重值\n",
    "print(f'最终拟合的权重 w: {w.data.item()}')\n"
   ],
   "id": "e72a0ee9dc4588c2"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "接下来，我们来考虑偏置bias",
   "id": "637395bdf2b9c7b9"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T13:05:51.074929Z",
     "start_time": "2025-06-18T13:05:49.598741Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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59R9+/bJNddcIzfeeGNIVx0t1Tb3S939dteuXUbdTabycuQD+WXSpElGEeQLL7xgFJfBX7qF9U9+8hOjyLdjx47ZvpxIaGhoMEaZHnroITnllFPk0ksvld/+9rfy4IMPZvvSCpIWP+rI0gMPPCCLFy+W559/Xl555RW54447sn1piNLIh/4F27RpU9m0aVOj4/q8rKzM8nf0uJvzkdn3bbrnnnuM8DF79mw58cQTA77SaH7fq1evlnXr1hnV7PE3R9WsWTNZsWKFdO/ePYQrj86fb13h0rx5c+P3TD179jT+jVGnFVq0aBH4dUfp+544caIRsH/+858bz3W14o4dO2TUqFFG6NNpG/jH7n5ZUlLiy6iHysv/xfT/2PpvG3PmzGn0l60+13lYK3o8/nz1+uuv256PzL5vdffddxv/ZjJr1izp27dvSFcbve9bl48vXbrUmHIxHxdeeKEMGjTI+Gddlgh//3wPHDjQmGoxQ55auXKlEUoIHv5/31ozlhgwzODH9mT+C+V+GcvjpVq69OrRRx81lgKNGjXKWKpVXV1tvP6Tn/wkNn78+EZLbZs1axa75557jKWft9xyC0ttA/y+J02aZCyle+6552JffPHFgcf27duz+N+icL/vRKx2Cfb7/vTTT43VW2PGjImtWLEiNnPmzNihhx4au/POO7P436Jwv2/9+1q/76eeespYBvrXv/411r17d2MVI9LTv3e17YE+9LZ/7733Gv+8fv1643X9rvU7T1xq+5vf/Ma4X2rbBJbaxtG1x127djVucrp0a+HChQdeO/vss42/gOM9++yzsWOPPdY4X5cRvfLKK1m46mh830ceeaTxhzzxoX+JIJg/3/EIH8F/3++8846xXF9vorrs9ne/+52x3Bn+f9979+6N3XrrrUbgaNmyZaxLly6xa6+9NrZ169YsXX1+mTt3ruXfx+Z3rD/1O0/8nT59+hj/++if70ceecTXayrS//BvHAUAAKAAaz4AAED+InwAAIBQET4AAECoCB8AACBUhA8AABAqwgcAAAgV4QMAAISK8AEAAEJF+AAAAKEifAAAgFARPgAAQKgIHwAAQML0/wF+m3wCnynVIwAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最终拟合的权重 w: 12.260981559753418\n"
     ]
    }
   ],
   "execution_count": 27,
   "source": [
    "import torch\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 数据准备\n",
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.rand() * 100 for i in x])\n",
    "y = y + 100\n",
    "\n",
    "# 将数据归一化到 [0,1] 范围内\n",
    "x = x / 100.0\n",
    "y = y / 100.0\n",
    "\n",
    "# 将 NumPy 数组转换为 PyTorch 张量\n",
    "x_tensor = torch.tensor(x, dtype=torch.float32)\n",
    "y_tensor = torch.tensor(y, dtype=torch.float32)\n",
    "\n",
    "# 初始化模型参数 w 为可学习的 Parameter，设置 requires_grad=True，表示w参数需要求导，需要计算梯度\n",
    "w = torch.nn.Parameter(torch.tensor(0.1, dtype=torch.float32), requires_grad=True)\n",
    "\n",
    "# 定义优化器 (SGD - 随机梯度下降)\n",
    "optimizer = torch.optim.SGD([w], lr=0.01)  # learning_rate = 0.01   # w = w - lr*w.grad\n",
    "\n",
    "# 训练循环\n",
    "epochs = 200\n",
    "for _ in range(epochs):\n",
    "    # 遍历每个样本\n",
    "    for i in range(len(x_tensor)):\n",
    "\n",
    "        # 前向传播: 计算预测值\n",
    "        y_predict = w * x_tensor[i]\n",
    "\n",
    "        # 损失函数: 平方误差\n",
    "        loss = (y_predict - y_tensor[i]) ** 2\n",
    "\n",
    "        loss.backward()     # 反向传播\n",
    "        optimizer.step()  # 更新参数w的值\n",
    "        optimizer.zero_grad()  # 清除w之前的梯度\n",
    "\n",
    "# 最终预测结果\n",
    "final_prediction = w.data.item() * x_tensor\n",
    "\n",
    "# 绘图\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, final_prediction.numpy(), color='r')\n",
    "plt.show()\n",
    "\n",
    "# 输出最终的权重值\n",
    "print(f'最终拟合的权重 w: {w.data.item()}')\n"
   ],
   "id": "5c4d86012eb6f86f"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "不管怎么选了，都不能拟合前面一部分数据，导致直线方向不对",
   "id": "fd5994816a4ae2af"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T13:08:39.459871Z",
     "start_time": "2025-06-18T13:08:38.215440Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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NL/33nv9Bx10kPHPetu+fXvgnKOPPtr/yiuvBO4/9NBD/oMPPtg/e/Zs/+eff+4vLCz05+fn+3///fcU/a/IHP369fN36dLF/9FHH/kXL17sb9eunX/QoEGBx7///nvj89bH1e7du/1t27b1n3766caxdevW+R955BGjon3evHkp/F+SnZ+3euyxx/wNGzb0v/TSS/61a9caK1/q1KljfPZw//MOx2qXxH3epaWlxgqMTp06Gf8+6+oi87Z3794U/i9JPzNmzDBWcU6bNs1YWXTDDTcY33vFxcXG41dddZV/1KhRgfM/+OADf40aNYzfz19++aX/7rvv9tesWdO/cuVK164pq8LHNddcY/zHHn5btGhR4By9r0txg5fbjhkzxn/YYYcZ/88566yz/F9//XWK/hdkli1bthi/HDTo6Rfc4MGDQ4Lehg0bIj7/NWvW+C+44AJ/s2bN/PXq1fMff/zxEUtv4d7nrXQ5XcuWLY3Pu6CgwP/++++n4Oq983kHI3wk7vPWn1a/7/Wm5yLUE0884T/iiCOMpci69HbJkiWBx8444wzj+zN82XL79u2N84899ljX/0D06f9xbxwFAAAgw1e7AACA7EL4AAAASUX4AAAASUX4AAAASUX4AAAASUX4AAAASUX4AAAASUX4AAAASUX4AAAASUX4AAAASUX4AAAASUX4AAAAkkz/Hxk4wu94bmu2AAAAAElFTkSuQmCC"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最终拟合的权重 w: -10.171807289123535\n"
     ]
    }
   ],
   "execution_count": 29,
   "source": [
    "import torch\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 数据准备\n",
    "x = -1 * np.random.randint(1, 100, 100)\n",
    "y = -1 * np.array([i * 10 + np.random.rand() * 100 for i in x])\n",
    "y = y + 100\n",
    "\n",
    "# 将数据归一化到 [0,1] 范围内\n",
    "x = x / 100.0\n",
    "y = y / 100.0\n",
    "\n",
    "# 将 NumPy 数组转换为 PyTorch 张量\n",
    "x_tensor = torch.tensor(x, dtype=torch.float32)\n",
    "y_tensor = torch.tensor(y, dtype=torch.float32)\n",
    "\n",
    "# 初始化模型参数 w 为可学习的 Parameter，设置 requires_grad=True，表示w参数需要求导，需要计算梯度\n",
    "w = torch.nn.Parameter(torch.tensor(0.1, dtype=torch.float32), requires_grad=True)\n",
    "b = torch.nn.Parameter(torch.tensor(0.1, dtype=torch.float32), requires_grad=True)\n",
    "\n",
    "# 定义优化器 (SGD - 随机梯度下降)\n",
    "optimizer = torch.optim.SGD([w, b], lr=0.01)  # learning_rate = 0.01   # w = w - lr*w.grad\n",
    "\n",
    "# 训练循环\n",
    "epochs = 200\n",
    "for _ in range(epochs):\n",
    "    # 遍历每个样本\n",
    "    for i in range(len(x_tensor)):\n",
    "\n",
    "        # 前向传播: 计算预测值\n",
    "        y_predict = w * x_tensor[i] + b\n",
    "\n",
    "        # 损失函数: 平方误差\n",
    "        loss = (y_predict - y_tensor[i]) ** 2\n",
    "\n",
    "        loss.backward()     # 反向传播\n",
    "        optimizer.step()  # 更新参数w、b的值\n",
    "        optimizer.zero_grad()  # 清除w之前的梯度\n",
    "\n",
    "# 最终预测结果\n",
    "final_prediction = w.data.item() * x_tensor + b.data.item()\n",
    "\n",
    "# 绘图\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, final_prediction.numpy(), color='r')\n",
    "plt.show()\n",
    "\n",
    "# 输出最终的权重值\n",
    "print(f'最终拟合的权重 w: {w.data.item()}')\n"
   ],
   "id": "5417bb360902b197"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "这下，我们的模型中就由了w和b两个参数，对于模型训练来说，就需要找到w和b最合适的值，使得训练出来的函数在样本集上误差最小，如何找到w和b呢，就是根据误差公式分别对w和b进行求导，也就是求梯度，然后逐步更新w和b的值，直到最低点。",
   "id": "458e34689eeb6c32"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## loss.backward()是怎么求导的？\n",
    "\n",
    "loss表面上看只是一个数字，那么为什么backward()能求导了呢？它是怎么知道我的误差函数的呢？\n",
    "\n",
    "在PyTorch中，有一个机制叫做：动态计算图，这个图记录了张量之间的运算关系，例如\n",
    "```python\n",
    "y_pred = w * x + b\n",
    "loss = (y_pred - y) ** 2\n",
    "```\n",
    "这段代码定义了一个简单的误差函数（平方误差）。PyTorch 会将这些运算记录下来，并保存对应的梯度规则。\n",
    "\n",
    "在调用 loss.backward() 时，PyTorch 会从 loss 开始，按照计算图中的依赖关系，使用链式法则逐层计算梯度。例如，在上述平方误差的例子中：\n",
    "首先，PyTorch 会找到 loss 的表达式：$\\text{loss} = (w \\cdot x + b - y)^2$。\n",
    "然后，根据链式法则，分别计算： $$ \\frac{\\partial \\text{loss}}{\\partial w} = 2(w \\cdot x + b - y) \\cdot x $$ $$ \\frac{\\partial \\text{loss}}{\\partial b} = 2(w \\cdot x + b - y) $$\n",
    "最终，这些梯度会被存储在对应的张量中（如 w.grad 和 b.grad）。\n",
    "\n",
    "我们在定义x和y时，没有指定requires_grad=True，所以PyTorch不会计算x和y的梯度。"
   ],
   "id": "54c0a1b0d60a1e6a"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T12:01:43.766988Z",
     "start_time": "2025-06-18T12:01:43.763102Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "梯度 dw: -3.5999999046325684, db: -3.5999999046325684\n",
      "梯度 dx: None, dy: None\n"
     ]
    }
   ],
   "execution_count": 8,
   "source": [
    "import torch\n",
    "\n",
    "# 定义参数和数据\n",
    "x = torch.tensor(1, requires_grad=False)\n",
    "y = torch.tensor(2, requires_grad=False)\n",
    "w = torch.tensor(0.1, requires_grad=True)\n",
    "b = torch.tensor(0.1, requires_grad=True)\n",
    "\n",
    "# 前向传播\n",
    "y_pred = w * x + b\n",
    "loss = (y_pred - y).pow(2)\n",
    "\n",
    "# 反向传播\n",
    "loss.backward()\n",
    "print(f\"梯度 dw: {w.grad}, db: {b.grad}\")\n",
    "print(f\"梯度 dx: {x.grad}, dy: {y.grad}\")"
   ],
   "id": "da559a36ab4b4686"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## optimizer.zero_grad()为什么梯度要清零？\n",
    "为什么要清除梯度，不清清除度会怎么样？\n",
    "\n",
    "梯度表示了参数调整的方向和大小，如果不清除梯度，会导致第二次计算出来的梯度加了第一次计算出来的梯度，可能导致方向和大小都有问题，使得模型训练不出来。"
   ],
   "id": "2a7a8c046dfb8ea6"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T12:02:26.437799Z",
     "start_time": "2025-06-18T12:02:26.433956Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "梯度 dw: -3.5999999046325684, db: -3.5999999046325684\n",
      "梯度 dw: -3.5999999046325684, db: -7.199999809265137\n"
     ]
    }
   ],
   "execution_count": 11,
   "source": [
    "import torch\n",
    "\n",
    "# 定义参数和数据\n",
    "x = torch.tensor(1, requires_grad=False)\n",
    "y = torch.tensor(2, requires_grad=False)\n",
    "w = torch.tensor(0.1, requires_grad=True)\n",
    "b = torch.tensor(0.1, requires_grad=True)\n",
    "\n",
    "# 前向传播\n",
    "y_pred = w * x + b\n",
    "loss = (y_pred - y).pow(2)\n",
    "\n",
    "# 反向传播\n",
    "loss.backward(retain_graph=True)\n",
    "print(f\"梯度 dw: {w.grad}, db: {b.grad}\")\n",
    "\n",
    "# 梯度清零\n",
    "w.grad.zero_()\n",
    "\n",
    "# 梯度累加\n",
    "loss.backward(retain_graph=True)\n",
    "print(f\"梯度 dw: {w.grad}, db: {b.grad}\")"
   ],
   "id": "6a3bd576390aa5d5"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## optimizer.step()如何更新参数？\n",
    "在optimizer.step()之前，已经计算了各个参数的梯度，接下来按照指定的算法来更新参数就可以了，比如SGD的更新公式为：\n",
    "$$ \\theta_{\\text{new}} = \\theta_{\\text{old}} - \\eta \\cdot g $$\n",
    "其中：\n",
    "$\\theta$：模型参数。\n",
    "$\\eta$：学习率（learning rate），控制每次更新的步长。\n",
    "$g$：当前参数对应的梯度。\n"
   ],
   "id": "886faf9b39a90dd7"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "将上述代码改成mini-batch SGD",
   "id": "2db6fba661e0c765"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T13:14:17.974200Z",
     "start_time": "2025-06-18T13:14:17.960442Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.38 0.39 0.41 0.48 0.68 0.44 0.89 0.1  0.09 0.58 0.25 0.62 0.23 0.04\n",
      " 0.07 0.44]\n",
      "[ 5.76460777  5.52254747  5.97929155  6.52056775  8.41687707  5.55359688\n",
      " 10.76442379  2.56347122  2.30029981  7.72274992  4.32264835  7.95595287\n",
      "  3.33162741  2.12223403  2.39160126  5.61032134]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(tensor([0.3800, 0.3900, 0.4100, 0.4800, 0.6800, 0.4400, 0.8900, 0.1000, 0.0900,\n",
       "         0.5800, 0.2500, 0.6200, 0.2300, 0.0400, 0.0700, 0.4400]),\n",
       " tensor([ 5.7646,  5.5225,  5.9793,  6.5206,  8.4169,  5.5536, 10.7644,  2.5635,\n",
       "          2.3003,  7.7227,  4.3226,  7.9560,  3.3316,  2.1222,  2.3916,  5.6103]))"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 34,
   "source": [
    "import torch\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from torch.utils.data import TensorDataset, DataLoader\n",
    "\n",
    "# 大都督周瑜（我的微信: dadudu6789）\n",
    "\n",
    "# 数据准备\n",
    "x = np.random.randint(1, 100, 100)\n",
    "y = np.array([i * 10 + np.random.rand() * 100 for i in x])\n",
    "y = y + 100\n",
    "\n",
    "# 将数据归一化到 [0,1] 范围内\n",
    "x = x / 100.0\n",
    "y = y / 100.0\n",
    "\n",
    "# 将 NumPy 数组转换为 PyTorch 张量，并增加一个维度以适应模型要求 (shape: [batch_size, features])\n",
    "x_tensor = torch.tensor(x, dtype=torch.float32)\n",
    "y_tensor = torch.tensor(y, dtype=torch.float32)\n",
    "\n",
    "# 创建数据集和数据加载器（DataLoader），定义 batch_size=16\n",
    "dataset = TensorDataset(x_tensor, y_tensor)\n",
    "print(x[:16])\n",
    "print(y[:16])\n",
    "dataset[:16]"
   ],
   "id": "4c0bbaf2f3358a54"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T13:15:26.726371Z",
     "start_time": "2025-06-18T13:15:26.722669Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0.0600, 0.0700, 0.7600, 0.3600, 0.0400])\n",
      "tensor([2.3570, 2.3916, 8.7871, 5.0476, 2.0751])\n"
     ]
    }
   ],
   "execution_count": 43,
   "source": [
    "dataloader = DataLoader(dataset, batch_size=5, shuffle=True)\n",
    "for x_batch, y_batch in dataloader:\n",
    "    print(x_batch)\n",
    "    print(y_batch)\n",
    "    break"
   ],
   "id": "f91a81e32aacb8be"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-18T13:19:48.220492Z",
     "start_time": "2025-06-18T13:19:47.833649Z"
    }
   },
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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P/7xD9/nn3/uu/baa33NmjXzbd682fL69957z5eXl+ebMGGCb8WKFb67777b16BBA9+yZcsSfu/pzu17f+WVV/oee+wx3yeffOL74osvfL/4xS98RUVFvq+++irh955t772poqLCd8QRR/h+/OMf+4YMGZKw+83m976mpsZ3yimn+C688ELfokWLjF+DBQsW+JYuXZrwe8+m9/2FF17wFRQUGN/1PX/jjTd8bdq08Y0cOTLh957uXnvtNd9dd93lmz59uq5u9c2YMSPs9evWrfM1btzYd+uttxqfs3/961+Nz925c+d6dk9JDx89e/b0jRgxov5xbW2tr6SkxDdu3DjL6y+99FLfgAEDAo6ddtppvt/85jdxv9dM4/a9D3bw4EFf06ZNfVOmTInjXWamaN57fb979+7t+/vf/+4bPnw44SNB7/2kSZN8Rx99tG///v0JvMvM4/Z912vPPvvsgGP6YdinT5+432smEwfh4/bbb/cdd9xxAccuu+wy33nnnefZfSR12GX//v3y8ccfG+V7/71d9HF5ebnlz+hx/+vVeeedZ3s9vHvvg+3Zs0cOHDggLVq0iOOdZp5o3/s//vGP0rp1a/nVr36VoDvNPNG897NmzZJevXoZwy6HH364dOvWTR588EGpra1N4J1n3/veu3dv42fMoZl169YZQ10XXnhhwu47W5Un4HM2qRvLbdmyxfgDrH+g/enjL7/80vJnKisrLa/X44jvex+srKzMGEMM/k0K79/7RYsWydNPPy1Lly5N0F1mpmjee/3Qmz9/vgwdOtT48FuzZo3ceOONRvDWjpCIz/t+5ZVXGj/Xt29fY7fUgwcPyvXXXy933nlngu46e1XafM7qzrd79+415uBkxIRTpJ+HHnrImPg4Y8YMY/IY4ke3qB42bJgx4bdVq1bJvp2sU1dXZ1ScJk+eLCeffLJcdtllctddd8kTTzyR7FvLaDrhUStMjz/+uCxZskSmT58uc+bMkbFjxyb71pDulQ/9izQvL082b94ccFwfFxcXW/6MHndzPbx7700PP/ywET7mzZsnxx9/fJzvNPO4fe/Xrl0r69evN2ar+38gqsMOO0xWrlwpHTp0SMCdZ+fve13h0qBBA+PnTMcee6zxr0MdTsjPz4/7fWfj+z569GgjdP/61782HuvKxt27d8t1111nhD8dtkF82H3OFhYWelL1UEn91dM/tPovibfeeivgL1V9rGOsVvS4//XqzTfftL0e3r33asKECca/PObOnSunnHJKgu42u997XVa+bNkyY8jF/Bo8eLD069fP+G9dgoj4/b7v06ePMdRiBj61atUqI5QQPOL3vuucsuCAYQZAtiSLr4R8zvpSYPmVLqd69tlnjSU91113nbH8qrKy0jg/bNgw3x133BGw1Pawww7zPfzww8Zyz3vvvZeltgl67x966CFjqdxLL73k+/bbb+u/du7cmcT/F9nx3gdjtUvi3vuNGzcaq7puuukm38qVK32zZ8/2tW7d2nf//fcn8f9F5r/v+ne7vu9Tp041ln7+5z//8XXo0MFY8Qh39O9obZGgX/qx/8gjjxj/vWHDBuO8vu/6/gcvtb3tttuMz1ltsZBxS22VriE+8sgjjQ82XY71wQcf1J8788wzjb9o/f3rX//yderUybhelwPNmTMnCXedGdy890cddZTxGzf4S/+SQPx/3/sjfCT2vX///feNJf364anLbh944AFj6TPi974fOHDAN2bMGCNwNGzY0NeuXTvfjTfe6Nu+fXuS7j59vf3225Z/d5vvt37X9z/4Z3r06GH8Wunv+WeeecbTe8rR//GujgIAABAeM3YAAEBCET4AAEBCET4AAEBCET4AAEBCET4AAEBCET4AAEBCET4AAEBCET4AAEBCET4AAEBCET4AAEBCET4AAEBCET4AAIAk0v8Hvfq6vNdXIYkAAAAASUVORK5CYII="
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最终拟合的权重 w: 10.144980430603027\n",
      "最终拟合的权重 b: 1.5215063095092773\n"
     ]
    }
   ],
   "execution_count": 50,
   "source": [
    "# 初始化模型参数 w 和 b\n",
    "w = torch.nn.Parameter(torch.tensor(0.1, dtype=torch.float32), requires_grad=True)\n",
    "b = torch.nn.Parameter(torch.tensor(0.1, dtype=torch.float32), requires_grad=True)\n",
    "\n",
    "# 定义优化器 (SGD - 随机梯度下降)\n",
    "optimizer = torch.optim.SGD([w, b], lr=0.1)  # 可适当提高学习率\n",
    "\n",
    "criterion = torch.nn.MSELoss()\n",
    "\n",
    "# 训练循环\n",
    "epochs = 200\n",
    "for epoch in range(epochs):\n",
    "    for x_batch, y_batch in dataloader:\n",
    "        # 前向传播: 批量预测\n",
    "        y_predict = w * x_batch + b\n",
    "\n",
    "        # 损失函数: 均方误差（MSE）\n",
    "        # loss = ((y_predict - y_batch) ** 2).mean()  # 对 batch 中的损失取平均\n",
    "        loss = criterion(y_predict, y_batch)\n",
    "\n",
    "        # 反向传播和优化\n",
    "        loss.backward()  # 计算当前 batch 下 w 和 b 的梯度\n",
    "        optimizer.step()  # 更新参数\n",
    "        optimizer.zero_grad()  # 清除上一次的梯度\n",
    "\n",
    "# 最终预测结果 一行就是一个样本的预测结果，所以进行行转列，从而变成一个数组\n",
    "final_prediction = (w.data.item() * x_tensor + b.data.item())\n",
    "\n",
    "# 绘图\n",
    "plt.scatter(x, y)\n",
    "plt.plot(x, final_prediction.numpy(), color='r')\n",
    "plt.show()\n",
    "\n",
    "# 输出最终的权重值\n",
    "print(f'最终拟合的权重 w: {w.data.item()}')\n",
    "print(f'最终拟合的权重 b: {b.data.item()}')\n"
   ],
   "id": "bbb055a61ac981d"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.20"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
